package controllers

import (
	"encoding/json"
	"fmt"
	"ginclassmates/models"
	"ginclassmates/utils"
	"log"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/Shopify/sarama"
	"github.com/gin-gonic/gin"
	"github.com/tealeg/xlsx"
)

var wg sync.WaitGroup

// 测试
// @Summary 测试函数
// @Description 这是一个用于测试的函数
// @Produce plain
// @Success 200 {string} string "测试！"
// @Router /test [get]
func Test(this *gin.Context) {
	this.String(200, "测试！")
}

// @Summary 学生签到
// @Description 接收学生的签到信息，核对信息后发送到 Kafka 中，并等待 Kafka 返回签到结果
// @Accept x-www-form-urlencoded
// @Produce plain
// @Param name formData string true "学生姓名"
// @Param number formData string true "学生学号"
// @Param class formData string true "学生班级"
// @Success 200 {string} string "签到成功！"
// @Failure 400 {string} string "信息出错！没有学号为：%v这个同学的信息！"
// @Failure 400 {string} string "考勤信息添加错误！"
// @Failure 400 {string} string "考勤信息获取错误！"
// @Router /sign-up [post]
// 读取上传得配置文件信息提取其中的数据
func Sign_in(this *gin.Context) {
	/* name := this.PostForm("name")
	number := this.PostForm("number")
	class := this.PostForm("class") */
	var req models.SignUpRequest
	if err := this.BindJSON(&req); err != nil {
		this.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	//获取到信息后进行信息核对
	//判断输入的信息是否有误
	//判断输入的学号是否存在
	err := models.JudgmentNumber(req.Number, req.Name)
	if err != nil {
		this.String(400, fmt.Sprintf("信息出错！没有学号为：%v这个同学的信息！", req.Number))
		return
	}
	//将接受到的正确数据封装到结构体中，发送到kafka中
	signin_User := models.Signin_User{
		Number:      req.Number,
		Name:        req.Name,
		Class:       req.Class,
		Create_Time: time.Now(),
	}
	//序列化后将这个数据推送到发送kafka消息管道中
	data, err := json.Marshal(signin_User)
	if err != nil {
		this.String(400, fmt.Sprintf("考勤信息添加错误！err:"+err.Error()))
		log.Println(err)
		return
	}
	models.Messages <- &sarama.ProducerMessage{
		Topic: utils.Kafkatopic,
		Value: sarama.ByteEncoder(data),
		Key:   sarama.StringEncoder(utils.Kafkakey),
	}
	//将学号作为订阅器的key值
	subscribe := models.RedisSubscribe(req.Number)

	//订阅频道是否有新消息出现
	if _, err = subscribe.Receive(); err != nil {
		this.String(400, fmt.Sprintf("考勤信息获取错误！err:"+err.Error()))
		log.Println(err)
		return
	}
	//需求只需要获取一条消息
	ch := subscribe.Channel()
	defer subscribe.Close()
	for msg := range ch {

		fmt.Printf("处理的结果消息是: %v\n", msg.Payload)
		//this.String(200, msg.Payload)
		data := []models.Signin_User{}
		json.Unmarshal([]byte(msg.Payload), &data)
		this.String(200, msg.Payload)
		//this.JSON(200, gin.H{"data": data})
		break

	}
}

// @Summary 提取 Excel 文件中的学生信息
// @Description 从上传的 Excel 文件中提取学生的学号和姓名信息，并将其添加到数据库中
// @Accept multipart/form-data
// @Produce plain
// @Param file formData file true "Excel 文件"
// @Success 200 {string} string "文件内容读取成功！"
// @Failure 400 {string} string "err"
// @Router /readfile [post]
func ExtractData(c *gin.Context) {
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		c.String(http.StatusBadRequest, fmt.Sprintf("err: %s", err.Error()))
		return
	}
	defer file.Close()

	// 获取文件名和扩展名
	filename := header.Filename
	ext := filepath.Ext(filename)

	// 判断文件类型是否为excel文件
	if ext != ".xlsx" && ext != ".xls" {
		c.String(http.StatusBadRequest, "你需要提交的是一个execl文件!")
		return
	}

	// 读取excel文件
	wb, err := xlsx.OpenReaderAt(file, header.Size)
	if err != nil {
		c.String(http.StatusBadRequest, fmt.Sprintf("err: %s", err.Error()))
		return
	}
	// 定义一个数组，用于保存所有学生的学号和姓名
	//var students [][]string
	// 遍历每个工作表
	NumberInformation, NameInformation := make([]string, 0), make([]string, 0)
	number := -1
	numbername := -1
	ip := 40
	for _, sheet := range wb.Sheets {
		// 遍历每行数据

		for _, row := range sheet.Rows {
			// studentID := ""
			// name := ""
			// 遍历每个单元格数据

			for i, cell := range row.Cells {
				val := cell.Value

				switch {
				case number == i:
					NumberInformation = append(NumberInformation, strings.TrimSpace(val))
				case numbername == i:
					NameInformation = append(NameInformation, strings.TrimSpace(val))
				case strings.TrimSpace(val) == "学号":
					number = i
				case strings.TrimSpace(val) == "姓名":
					numbername = i
				default:
					continue
				}

			}

		}

	}
	var Err []string
	Time := time.Now()
	for i := 0; i < len(NumberInformation); i++ {
		wg.Add(1)
		//将学号姓名数据添加到数据库中
		go func(i int) {
			defer wg.Done()
			err := models.MYSQL_ExtractData(NumberInformation[i], NameInformation[i], strconv.Itoa(ip))
			if err != nil {
				Err = append(Err, fmt.Sprintf("学号为："+NumberInformation[i]+",姓名为:"+NameInformation[i]+"信息存入错误！\n"))
				log.Println("学号为：" + NumberInformation[i] + ",姓名为:" + NameInformation[i] + "信息存入错误！\n")
			} else {
				models.Redisread(models.ReadUser{
					Number: NumberInformation[i],
					Name:   NameInformation[i],
					Ip:     strconv.Itoa(ip),
				})
			}

		}(i)
		ip++
	}
	wg.Wait()
	c.String(http.StatusOK, fmt.Sprintf("总共获取了%v位同学信息\n", len(NumberInformation)))
	c.String(http.StatusOK, fmt.Sprintf("其中存入错的的同学有：\n"+strconv.Itoa(len(Err))+"个同学！\n"))
	//fmt.Println("总共获取了多少位同学信息", len(NumberInformation))
	// 处理完毕，返回成功响应
	c.String(http.StatusOK, fmt.Sprintf("耗时：%v\n", time.Since(Time)))
	c.String(http.StatusOK, fmt.Sprintf("文件内容读取成功！文件大小为：%vkb", header.Size/1024))
}
